﻿#pragma once
#include <vector>
#include <string>
#include <map>
using namespace std;
static int StringSplit(std::vector<std::string>& dst, const std::string& src, const std::string& separator)
{
	if (src.empty() || separator.empty())
		return 0;

	int nCount = 0;
	std::string temp;
	size_t pos = 0, offset = 0;

	while ((pos = src.find_first_of(separator, offset)) != std::string::npos)
	{
		temp = src.substr(offset, pos - offset);
		if (temp.length() > 0) {
			dst.push_back(temp);
			nCount++;
		}
		offset = pos + 1;
	}

	temp = src.substr(offset, src.length() - offset);
	if (temp.length() > 0) {
		dst.push_back(temp);
		nCount++;
	}

	return nCount;
}
static std::string& StringTrim(std::string& str)
{
	if (str.empty()) {
		return str;
	}
	str.erase(0, str.find_first_not_of(" "));
	str.erase(str.find_last_not_of(" ") + 1);
	return str;
}

static bool GetReqeustAndParmeter(std::string strUri, std::string& url, std::map<string, string>& lp)
{
	bool bRet = false;
	std::vector<std::string> vecRequest;
	int nRetSplit = StringSplit(vecRequest, strUri, "?");
	if (nRetSplit > 0)
	{
		if (vecRequest.size() == 1)
		{
			url = vecRequest[0];
		}
		else if (vecRequest.size() > 1)
		{
			url = vecRequest[0];
			std::string strRequestParameter = vecRequest[1];
			std::vector<std::string> vecParams;
			nRetSplit = StringSplit(vecParams, strRequestParameter, "&");
			if (nRetSplit > 0)
			{
				std::vector<std::string>::iterator iter, iterEnd;
				iter = vecParams.begin();
				iterEnd = vecParams.end();
				for (iter; iter != iterEnd; iter++)
				{
					std::vector<std::string> vecNameOrValue;
					nRetSplit = StringSplit(vecNameOrValue, *iter, "=");
					if (nRetSplit > 0)
					{
						if (vecNameOrValue.size() > 1)
							lp.insert(pair<string, string>(vecNameOrValue[0], vecNameOrValue[1]));
						else
							lp.insert(pair<string, string>(vecNameOrValue[0], ""));
					}
				}
			}
		}
	}
	return bRet;
}
static bool ReadFileContent(const char* pFilePath, const char* pReadMode, string& strContent)
{
	strContent.clear();
    FILE* fp = NULL;
	#ifdef  _WIN32
	fopen_s(&fp, pFilePath, pReadMode);
	#else
	fp = fopen(pFilePath,"r");
	#endif
	if (NULL == fp)
	{
		std::cout <<  pFilePath << " " << std::endl;
		return false;
	}
	fseek(fp, 0, SEEK_END);
	long nSize = ftell(fp);
	fseek(fp, 0, SEEK_SET);
	unsigned char* pBuffer = (unsigned char*)malloc(nSize);
	memset(pBuffer, 0, nSize);
	size_t nCount = fread(pBuffer, 1, nSize, fp);
	fclose(fp);
	strContent.assign((char*)pBuffer, nCount);
	free(pBuffer);
	return true;
}

//去除头文件依赖，直接编码  qianbo
static std::string base64_encode(const unsigned char* Data, int DataByte)
{
	//编码表  
	const char EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	//返回值  
	std::string str_encode;
	unsigned char tmp[4] = { 0 };
	int line_length = 0;
	for (int i = 0; i < (int)(DataByte / 3); i++)
	{
		tmp[1] = *Data++;
		tmp[2] = *Data++;
		tmp[3] = *Data++;
		str_encode += EncodeTable[tmp[1] >> 2];
		str_encode += EncodeTable[((tmp[1] << 4) | (tmp[2] >> 4)) & 0x3F];
		str_encode += EncodeTable[((tmp[2] << 2) | (tmp[3] >> 6)) & 0x3F];
		str_encode += EncodeTable[tmp[3] & 0x3F];
		if (line_length += 4, line_length == 76)
		{
			str_encode += "\r\n";
			line_length = 0;
		}
	}
	//对剩余数据进行编码  
	int mod = DataByte % 3;
	if (mod == 1)
	{
		tmp[1] = *Data++;
		str_encode += EncodeTable[(tmp[1] & 0xFC) >> 2];
		str_encode += EncodeTable[((tmp[1] & 0x03) << 4)];
		str_encode += "==";
	}
	else if (mod == 2)
	{
		tmp[1] = *Data++;
		tmp[2] = *Data++;
		str_encode += EncodeTable[(tmp[1] & 0xFC) >> 2];
		str_encode += EncodeTable[((tmp[1] & 0x03) << 4) | ((tmp[2] & 0xF0) >> 4)];
		str_encode += EncodeTable[((tmp[2] & 0x0F) << 2)];
		str_encode += "=";
	}

	return str_encode;
}


static inline bool is_base64(unsigned char c) {
	return (isalnum(c) || (c == '+') || (c == '/'));
}

static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";

static std::string base64_decode(std::string const& encoded_string) {
	size_t in_len = encoded_string.size();
	int i = 0;
	int j = 0;
	int in_ = 0;
	unsigned char char_array_4[4], char_array_3[3];
	std::string ret;

	while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
		char_array_4[i++] = encoded_string[in_]; in_++;
		if (i == 4) {
			for (i = 0; i < 4; i++)
				char_array_4[i] = (unsigned char)base64_chars.find(char_array_4[i]);

			char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
			char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
			char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

			for (i = 0; (i < 3); i++)
				ret += char_array_3[i];
			i = 0;
		}
	}

	if (i) {
		for (j = i; j < 4; j++)
			char_array_4[j] = 0;

		for (j = 0; j < 4; j++)
			char_array_4[j] = (unsigned char)base64_chars.find(char_array_4[j]);

		char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
		char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
		char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

		for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
	}

	return ret;
}

typedef std::map<std::string, std::string> c_header_map;

static uint32_t swap_endian(uint32_t& val) {
	val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0x00FF00FF);
	return (val << 16) | (val >> 16);
}
static uint64_t ntohll_1(uint64_t x) {
	const unsigned t = 1;
	if (*(const unsigned char*)&t) {

		uint32_t v = x & 0xffffffffU;
		uint32_t v1 = (uint32_t)(x >> 32);
		x = ((uint64_t)swap_endian(v) << 32)
			| swap_endian(v1);
	}
	return x;
}


/*
   lines :http protocol content lines   =>GET /live/1001
   buf   :let the url into this buffer  => live/1001
   buflen:the buf's length
*/
static int fetch_head_get(const char* lines, char* buf, int buflen)
{
	size_t l = strlen(lines);
	if (l < 6)
		return 0;
	//it is GET protocol
	if (strncmp(lines, "GET ", 4) != 0)
		return -1;
	char* pos = buf;
	//URL->GET /live/image ==> get the live/image to buf
#if 0
	char* ori = (char*)&lines[5];
	while (*(ori++) != ' ');
	size_t num = --ori - (lines + 5);
#endif
#define START_P 5
	for (size_t i = START_P; i < l, i < buflen + START_P; i++)
	{
		if (lines[i] == ' ')
			break;
		*pos++ = lines[i];
	}
	*pos = '\0';
	return (int)(pos - buf);
}
//ret is the /chat like this
// we must add the post protocol
static int fetch_head_info(std::string& lines, c_header_map& hmap, std::string& ret)
{
	if (strncmp(lines.c_str(), "GET ", 4) != 0)
		return -1;
	//not support now
	if (strncmp(lines.c_str(), "POST ", 5 == 0))
		return -2;
	std::istringstream s(lines);
	std::string request;
	std::getline(s, request);
	if (request[request.size() - 1] == '\r')
	{
		request.pop_back();
		//request.erase(request.end() - 1);//the same with pop_back
		//GET /chat HTTP/1.1
		size_t i = 5;
		size_t lmax = request.size();
		while (request[++i] != ' ' && i < lmax);
		if (i == lmax - 1)
			return -1;
		ret = request.substr(5, i - 5);
	}
	else
		return -1;

	hmap.clear();
	std::string header;
	std::string::size_type end;

	while (std::getline(s, header) && header != "\r")
	{
		if (header[header.size() - 1] == '\r')
		{
			//header.pop_back(); //or use this function
			header.erase(header.end() - 1); //remove last char
			end = header.find(": ", 0);

			if (end != std::string::npos)
			{
				std::string key = header.substr(0, end);
				std::string value = header.substr(end + 2);
				hmap[key] = value;
			}
		}
	}

	return 0;
}

